package com.wang.designpattern.singleton;

import org.apache.commons.lang3.SerializationUtils;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 双重检查懒汉式单例模式
 */
class Singleton03Test {
    public static void main(String[] args) {
        MyThread3 mt1 = new MyThread3("线程A ") ;    // 实例化对象
        MyThread3 mt2 = new MyThread3("线程B ") ;    // 实例化对象
        Thread t1 = new Thread(mt1) ;       // 实例化Thread类对象
        Thread t2 = new Thread(mt2) ;       // 实例化Thread类对象
        t1.start() ;    // 启动多线程
        t2.start() ;    // 启动多线程
        try {
            // 通过反射攻击单例模式
            Constructor<Singleton03> constructor = Singleton03.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Singleton03 newInstance = constructor.newInstance();
            System.out.println("反射 newInstance : " + newInstance.hashCode());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        // 通过反序列化攻击单例模式
        Singleton03 instance = Singleton03.getInstance();
        byte[] serialize = SerializationUtils.serialize(instance);
        Singleton03 newInstance = SerializationUtils.deserialize(serialize);
        System.out.println("反序列化 instance : " + instance.hashCode());
        System.out.println("反序列化 newInstance : " + newInstance.hashCode());
    }
}

class Singleton03 implements Serializable {
    private static volatile Singleton03 instance;

    private Singleton03() {}

    /*
    synchronized同步块括号中的锁定对象是采用的一个无关的Object类实例，而不是采用this，
    因为getInstance是一个静态方法，在它内部不能使用未静态的或者未实例的类对象
     */
    public static Singleton03 getInstance() {
        if (null == instance) {
            synchronized (Singleton03.class) {
                if (null == instance) {
                    instance = new Singleton03();
                }
            }
        }
        return instance;
    }
}

class MyThread3 implements Runnable{ // 实现Runnable接口，作为线程的实现类
    private String name ;       // 表示线程的名称
    public MyThread3(String name){
        this.name = name ;      // 通过构造方法配置name属性
    }
    public void run(){  // 覆写run()方法，作为线程 的操作主体、
        Singleton03 singleton = Singleton03.getInstance();
        System.out.println(name +  " " + singleton.hashCode());
    }
}